I. Preliminaries

Loading libraries

library("tidyverse")
library("tibble")
library("msigdbr")
library("ggplot2")
library("TCGAbiolinks")
library("RNAseqQC")
library("DESeq2")
library("ensembldb")
library("purrr")
library("magrittr")
library("vsn")
library("matrixStats")
library("dplyr")
library("grex")
library("biomaRt")

II. Downloading TCGA miRNA expression data

Download miRNA expression data from The Cancer Genome Atlas (TCGA): - TCGA-COAD refers to the biospecimen data for colon adenocarcinoma.

query_tumor <- GDCquery(
  project = "TCGA-COAD",
  data.category = "Transcriptome Profiling",
  data.type = "miRNA Expression Quantification",
  experimental.strategy = "miRNA-Seq",
  access = "open",
  sample.type = "Primary Tumor"
)
tumor <- getResults(query_tumor)
tumor
query_normal <- GDCquery(
  project = "TCGA-COAD",
  data.category = "Transcriptome Profiling",
  data.type = "miRNA Expression Quantification",
  experimental.strategy = "miRNA-Seq",
  access = "open",
  sample.type = "Solid Tissue Normal"
)
normal <- getResults(query_normal)
normal

Consider only samples with both normal and malignant tissues.

submitter_ids <- inner_join(tumor, normal, by = "cases.submitter_id") %>%
  dplyr::select(cases.submitter_id)
tumor <- tumor %>%
  dplyr::filter(cases.submitter_id %in% submitter_ids$cases.submitter_id)
normal <- normal %>%
  dplyr::filter(cases.submitter_id %in% submitter_ids$cases.submitter_id)

samples <- rbind(tumor, normal)
invisible(unique(samples$sample_type))
samples

Download only samples with both normal and malignant tissues.

To impose this filtering, we set the barcode argument of GDCquery to samples$sample.submitter_id (which was generated in the previous cell).

query_coad <- GDCquery(
  project = "TCGA-COAD",
  data.category = "Transcriptome Profiling",
  data.type = "miRNA Expression Quantification",
  experimental.strategy = "miRNA-Seq",
  access = "open",
  sample.type = c("Solid Tissue Normal", "Primary Tumor"),
  barcode = as.list(samples$sample.submitter_id)
)

If this is your first time running this notebook (i.e., you have not yet downloaded the results of the query in the previous block), uncomment the code block below.

GDC_DIR = "../data/public/GDCdata"

# GDCdownload(
#   query_coad,
#   directory = GDC_DIR
# )

Running the code block above should generate and populate a directory named GDCdata.

III. Data preprocessing

Construct the RNA-seq count matrix.

tcga_coad_data <- GDCprepare(
  query_coad, 
  directory = GDC_DIR,
  summarizedExperiment = TRUE
)
rownames(tcga_coad_data) <- tcga_coad_data$miRNA_ID
count_matrix <- tcga_coad_data[, colnames(tcga_coad_data)[grep("count", colnames(tcga_coad_data))]]
colnames(count_matrix) <- gsub("read_count_", "", colnames(count_matrix))

# Remove duplicate entries
count_matrix_df <- data.frame(count_matrix)
count_matrix_df <- count_matrix_df[!duplicated(count_matrix_df), ]
count_matrix <- data.matrix(count_matrix_df)
rownames(count_matrix) <- cleanid(rownames(count_matrix))
count_matrix <- count_matrix[!(duplicated(rownames(count_matrix)) | duplicated(rownames(count_matrix), fromLast = TRUE)), ]

head(count_matrix[1:5, 1:4])
             TCGA.A6.2684.01A.01T.1409.13 TCGA.A6.2671.01A.01T.1409.13 TCGA.AA.3520.01A.01T.0822.13 TCGA.A6.2680.01A.01T.1409.13
hsa-let-7a-1                        14506                        11763                         4503                         6055
hsa-let-7a-2                        14299                        11992                         4589                         5945
hsa-let-7a-3                        14183                        11822                         4619                         6018
hsa-let-7b                          31896                        15937                        19505                         9392
hsa-let-7c                           3130                         1488                          751                          141

Format the samples table so that it can be fed as input to DESeq2.

rownames(samples) <- samples$cases
samples <- samples %>%
  dplyr::select(case = "cases.submitter_id", type = "sample_type")
samples$type <- str_replace(samples$type, "Solid Tissue Normal", "normal")
samples$type <- str_replace(samples$type, "Primary Tumor", "tumor")

DESeq2 requires the row names of samples should be identical to the column names of count_matrix.

colnames(count_matrix) <- gsub(x = colnames(count_matrix), pattern = "\\.", replacement = "-")
count_matrix <- count_matrix[, rownames(samples)]

# Sanity check
all(colnames(count_matrix) == rownames(samples))

IV. Differential miRNA expression analysis

References:

Construct the DESeqDataSet object.

dds <- DESeqDataSetFromMatrix(
  countData = count_matrix,
  colData = samples,
  design = ~type
)
Warning: some variables in design formula are characters, converting to factors

Quality Control

Display quality control (QC) plots (refer to https://cran.r-project.org/web/packages/RNAseqQC/vignettes/introduction.html)

  • Total sample counts
    • Total number of counts for each sample
    • We typically expect all samples to have total counts within the same order of magnitude
  • Library complexity
    • What fraction of counts is taken up by what fraction of genes
    • Samples showing a different library complexity than the rest might be considered low quality
  • Gene detection
    • Number of detected genes for each sample

CAVEAT: There seem to be some outliers — but we defer handling them for now!

plot_total_counts(dds)

plot_library_complexity(dds)

plot_gene_detection(dds)

Perform miRNA filtering.

We determined min_count empirically by looking at the red trend line in the variance stabilization plot. Ideally, this trend line should be flat (i.e., stable).

dds <- filter_genes(dds, min_count = 10)

Transform the read counts.

From https://chipster.csc.fi/manual/deseq2-transform.html:
You can use the resulting transformed values only for visualization and clustering, not for differential expression analysis which needs raw counts.

dds <- estimateSizeFactors(dds)
nsub <- sum(rowMeans(counts(dds, normalized = TRUE)) > 10)
vsd <- vst(dds, nsub = nsub)
mean_sd_plot(vsd)

Check the clustering of the samples.

If you encounter the error Error in loadNamespace(x) : there is no package called 'ComplexHeatmap', uncomment and run the following code block:

# install.packages("devtools", dependencies = TRUE)
# devtools::install_github("jokergoo/ComplexHeatmap")
set.seed(42)
plot_sample_clustering(vsd, anno_vars = c("type"), distance = "euclidean")

Perform principal component analysis (PCA).

plot_pca(vsd, PC_x = 1, PC_y = 2, shape_by = "type")

Regulated Cell Death

Refer to 1. Exploratory Data Analysis - MSigDB Gene Sets + GTEx TPM.Rmd for more detailed documentation on obtaining the gene sets.

Mapping miRNAs to target mRNAs

We are going to refer to miRDB to for the miRNA-mRNA mapping: https://academic.oup.com/nar/article/48/D1/D127/5557729

The first column of the dataset lists the miRNAs, while the second column lists the mRNAs (more specifically, the RefSeq IDs of the mRNAs). However, our gene sets list the mRNAs of interest (i.e., those involved in regulated cell death) using their gene symbols.
Hence, we need to perform some preprocessing to convert the gene symbols to RefSeq IDs.

mart <- useMart(biomart = "ensembl", dataset = "hsapiens_gene_ensembl")

Alternative miRNA-mRNA mapping tools/databases:

Necroptosis

Fetch the necroptosis gene set.

necroptosis.genes <- msigdbr(species = "human", category = "C5", subcategory = "GO:BP") %>%
  dplyr::filter(gs_name == "GOBP_NECROPTOTIC_SIGNALING_PATHWAY")
necroptosis.genes

Get the gene symbols of the genes included in the necroptosis gene set, and convert them to RefSeq IDs.

rcd_gene_symbols <- necroptosis.genes$gene_symbol
rcd_refseq <- getBM(attributes = c("refseq_mrna", "hgnc_symbol"), filters = "hgnc_symbol", values = rcd_gene_symbols, mart = mart)
rcd_refseq

Write the RefSeq IDs of the mRNAs of interest to a file.

rcd_mrna_file <- "../data/public/rcd-gene-list/refseq/necroptosis-genes-refseq.txt"
rcd_refseq.unique_ids <- unique(unlist(rcd_refseq$refseq_mrna))
rcd_refseq.unique_ids <- rcd_refseq.unique_ids[!sapply(rcd_refseq.unique_ids, identical, "")]

# Regenerate the file every time
if (file.exists(rcd_mrna_file)) {
  file.remove(rcd_mrna_file)
}
invisible(lapply(rcd_refseq.unique_ids, write, rcd_mrna_file, append = TRUE, ncolumns = 1))

Fetch the miRNAs targeting the mRNAs of interest.

necroptosis.mirna <- read.table("../data/public/miRNA/necroptosis-mirna.txt")
necroptosis.mirna <- unique(unlist(necroptosis.mirna$V1))

Filter the genes to include only those in the necroptosis gene set.

coad_necroptosis <- count_matrix[rownames(count_matrix) %in% necroptosis.mirna, ]
coad_necroptosis <- coad_necroptosis[, rownames(samples)]

# Check if all samples in the counts dataframe are in the samples dataframe
all(colnames(coad_necroptosis) == rownames(samples))

Perform differential miRNA expression analysis.

dds <- DESeqDataSetFromMatrix(
  countData = coad_necroptosis,
  colData = samples,
  design = ~type
)
Warning: some variables in design formula are characters, converting to factors
dds <- filter_genes(dds, min_count = 10)
dds$type <- relevel(dds$type, ref = "normal")
dds <- DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 5 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
res <- results(dds)
summary(res)

out of 82 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 40, 49%
LFC < 0 (down)     : 36, 44%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

Prettify the display of results.

deseq.results <- res
deseq.bbl.data <- data.frame(
  row.names = rownames(deseq.results),
  baseMean = deseq.results$baseMean,
  log2FoldChange = deseq.results$log2FoldChange,
  lfcSE = deseq.results$lfcSE,
  stat = deseq.results$stat,
  pvalue = deseq.results$pvalue,
  padj = deseq.results$padj,
  cancer_type = "Colon"
)
deseq.bbl.data

Filter based on p-value and log fold change cutoffs.

deseq.bbl.data.filtered <- dplyr::filter(deseq.bbl.data, abs(log2FoldChange) >= 1.5 & padj < 0.05)
deseq.bbl.data.filtered

Plot the results.

ggplot(deseq.bbl.data.filtered, aes(x = cancer_type, y = rownames(deseq.bbl.data.filtered), size = padj, fill = log2FoldChange)) +
  geom_point(alpha = 0.5, shape = 21, color = "black") +
  scale_size(trans = "reverse") +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", limits = c(min(deseq.bbl.data.filtered$log2FoldChange), max(deseq.bbl.data.filtered$log2FoldChange))) +
  theme_minimal() +
  theme(legend.position = "bottom") +
  theme(legend.position = "bottom") +
  labs(size = "Adjusted p-value", fill = "log2 FC", x = "Cancer type", y = "miRNA")

Ferroptosis

Fetch the ferroptosis gene set.

ferroptosis.genes <- msigdbr(species = "human", category = "C2", subcategory = "CP:WIKIPATHWAYS") %>%
  dplyr::filter(gs_name == "WP_FERROPTOSIS")
ferroptosis.genes

Get the gene symbols of the genes included in the ferroptosis gene set, and convert them to RefSeq IDs.

rcd_gene_symbols <- ferroptosis.genes$gene_symbol
rcd_refseq <- getBM(attributes = c("refseq_mrna", "hgnc_symbol"), filters = "hgnc_symbol", values = rcd_gene_symbols, mart = mart)
rcd_refseq

Write the RefSeq IDs of the mRNAs of interest to a file.

rcd_mrna_file <- "../data/public/rcd-gene-list/refseq/ferroptosis-genes-refseq.txt"
rcd_refseq.unique_ids <- unique(unlist(rcd_refseq$refseq_mrna))
rcd_refseq.unique_ids <- rcd_refseq.unique_ids[!sapply(rcd_refseq.unique_ids, identical, "")]

# Regenerate the file every time
if (file.exists(rcd_mrna_file)) {
  file.remove(rcd_mrna_file)
}
invisible(lapply(rcd_refseq.unique_ids, write, rcd_mrna_file, append = TRUE, ncolumns = 1))

Fetch the miRNAs targeting the mRNAs of interest.

ferroptosis.mirna <- read.table("../data/public/miRNA/ferroptosis-mirna.txt")
ferroptosis.mirna <- unique(unlist(ferroptosis.mirna$V1))

Filter the genes to include only those in the ferroptosis gene set.

coad_ferroptosis <- count_matrix[rownames(count_matrix) %in% ferroptosis.mirna, ]
coad_ferroptosis <- coad_ferroptosis[, rownames(samples)]

# Check if all samples in the counts dataframe are in the samples dataframe
all(colnames(coad_ferroptosis) == rownames(samples))

Perform differential miRNA expression analysis.

dds <- DESeqDataSetFromMatrix(
  countData = coad_ferroptosis,
  colData = samples,
  design = ~type
)
Warning: some variables in design formula are characters, converting to factors
dds <- filter_genes(dds, min_count = 10)
dds$type <- relevel(dds$type, ref = "normal")
dds <- DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 13 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
res <- results(dds)
summary(res)

out of 256 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 114, 45%
LFC < 0 (down)     : 100, 39%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 4)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

Prettify the display of results.

deseq.results <- res
deseq.bbl.data <- data.frame(
  row.names = rownames(deseq.results),
  baseMean = deseq.results$baseMean,
  log2FoldChange = deseq.results$log2FoldChange,
  lfcSE = deseq.results$lfcSE,
  stat = deseq.results$stat,
  pvalue = deseq.results$pvalue,
  padj = deseq.results$padj,
  cancer_type = "Colon"
)
deseq.bbl.data

Filter based on p-value and log fold change cutoffs.

deseq.bbl.data.filtered <- dplyr::filter(deseq.bbl.data, abs(log2FoldChange) >= 1.5 & padj < 0.05)
deseq.bbl.data.filtered

Plot the results.

ggplot(deseq.bbl.data.filtered, aes(x = cancer_type, y = rownames(deseq.bbl.data.filtered), size = padj, fill = log2FoldChange)) +
  geom_point(alpha = 0.5, shape = 21, color = "black") +
  scale_size(trans = "reverse") +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", limits = c(min(deseq.bbl.data.filtered$log2FoldChange), max(deseq.bbl.data.filtered$log2FoldChange))) +
  theme_minimal() +
  theme(legend.position = "bottom") +
  theme(legend.position = "bottom") +
  labs(size = "Adjusted p-value", fill = "log2 FC", x = "Cancer type", y = "miRNA")

Pyroptosis

Fetch the pyroptosis gene set.

pyroptosis.genes <- msigdbr(species = "human", category = "C2", subcategory = "CP:REACTOME") %>%
  dplyr::filter(gs_name == "REACTOME_PYROPTOSIS")
pyroptosis.genes

Get the gene symbols of the genes included in the pyroptosis gene set, and convert them to RefSeq IDs.

rcd_gene_symbols <- pyroptosis.genes$gene_symbol
rcd_refseq <- getBM(attributes = c("refseq_mrna", "hgnc_symbol"), filters = "hgnc_symbol", values = rcd_gene_symbols, mart = mart)
rcd_refseq

Write the RefSeq IDs of the mRNAs of interest to a file.

rcd_mrna_file <- "../data/public/rcd-gene-list/refseq/pyroptosis-genes-refseq.txt"
rcd_refseq.unique_ids <- unique(unlist(rcd_refseq$refseq_mrna))
rcd_refseq.unique_ids <- rcd_refseq.unique_ids[!sapply(rcd_refseq.unique_ids, identical, "")]

# Regenerate the file every time
if (file.exists(rcd_mrna_file)) {
  file.remove(rcd_mrna_file)
}
invisible(lapply(rcd_refseq.unique_ids, write, rcd_mrna_file, append = TRUE, ncolumns = 1))

Fetch the miRNAs targeting the mRNAs of interest.

pyroptosis.mirna <- read.table("../data/public/miRNA/pyroptosis-mirna.txt")
pyroptosis.mirna <- unique(unlist(pyroptosis.mirna$V1))

Filter the genes to include only those in the pyroptosis gene set.

coad_pyroptosis <- count_matrix[rownames(count_matrix) %in% pyroptosis.mirna, ]
coad_pyroptosis <- coad_pyroptosis[, rownames(samples)]

# Check if all samples in the counts dataframe are in the samples dataframe
all(colnames(coad_pyroptosis) == rownames(samples))

Perform differential miRNA expression analysis.

dds <- DESeqDataSetFromMatrix(
  countData = coad_pyroptosis,
  colData = samples,
  design = ~type
)
Warning: some variables in design formula are characters, converting to factors
dds <- filter_genes(dds, min_count = 10)
dds$type <- relevel(dds$type, ref = "normal")
dds <- DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 9 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
res <- results(dds)
summary(res)

out of 184 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 84, 46%
LFC < 0 (down)     : 71, 39%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 4)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

Prettify the display of results.

deseq.results <- res
deseq.bbl.data <- data.frame(
  row.names = rownames(deseq.results),
  baseMean = deseq.results$baseMean,
  log2FoldChange = deseq.results$log2FoldChange,
  lfcSE = deseq.results$lfcSE,
  stat = deseq.results$stat,
  pvalue = deseq.results$pvalue,
  padj = deseq.results$padj,
  cancer_type = "Colon"
)
deseq.bbl.data

Filter based on p-value and log fold change cutoffs.

deseq.bbl.data.filtered <- dplyr::filter(deseq.bbl.data, abs(log2FoldChange) >= 1.5 & padj < 0.05)
deseq.bbl.data.filtered

Plot the results.

ggplot(deseq.bbl.data.filtered, aes(x = cancer_type, y = rownames(deseq.bbl.data.filtered), size = padj, fill = log2FoldChange)) +
  geom_point(alpha = 0.5, shape = 21, color = "black") +
  scale_size(trans = "reverse") +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", limits = c(min(deseq.bbl.data.filtered$log2FoldChange), max(deseq.bbl.data.filtered$log2FoldChange))) +
  theme_minimal() +
  theme(legend.position = "bottom") +
  theme(legend.position = "bottom") +
  labs(size = "Adjusted p-value", fill = "log2 FC", x = "Cancer type", y = "miRNA")


  1. De La Salle University, Manila, Philippines, ↩︎

  2. De La Salle University, Manila, Philippines, ↩︎

LS0tDQp0aXRsZTogIkRpZmZlcmVudGlhbCBtaVJOQSBFeHByZXNzaW9uIEFuYWx5c2lzIg0Kc3VidGl0bGU6ICJDb2xvcmVjdGFsIENhbmNlciB8IE5lY3JvcHRvc2lzLCBGZXJyb3B0b3NpcyAmIFB5cm9wdG9zaXMiDQphdXRob3I6IA0KICAtIE1hcmsgRWR3YXJkIE0uIEdvbnphbGVzXltEZSBMYSBTYWxsZSBVbml2ZXJzaXR5LCBNYW5pbGEsIFBoaWxpcHBpbmVzLCBnb256YWxlcy5tYXJrZWR3YXJkQGdtYWlsLmNvbV0NCiAgLSBEci4gQW5pc2ggTS5TLiBTaHJlc3RoYV5bRGUgTGEgU2FsbGUgVW5pdmVyc2l0eSwgTWFuaWxhLCBQaGlsaXBwaW5lcywgYW5pc2guc2hyZXN0aGFAZGxzdS5lZHUucGhdDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyBJLiBQcmVsaW1pbmFyaWVzDQoNCiMjIyBMb2FkaW5nIGxpYnJhcmllcw0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KCJ0aWJibGUiKQ0KbGlicmFyeSgibXNpZ2RiciIpDQpsaWJyYXJ5KCJnZ3Bsb3QyIikNCmxpYnJhcnkoIlRDR0FiaW9saW5rcyIpDQpsaWJyYXJ5KCJSTkFzZXFRQyIpDQpsaWJyYXJ5KCJERVNlcTIiKQ0KbGlicmFyeSgiZW5zZW1ibGRiIikNCmxpYnJhcnkoInB1cnJyIikNCmxpYnJhcnkoIm1hZ3JpdHRyIikNCmxpYnJhcnkoInZzbiIpDQpsaWJyYXJ5KCJtYXRyaXhTdGF0cyIpDQpsaWJyYXJ5KCJkcGx5ciIpDQpsaWJyYXJ5KCJncmV4IikNCmxpYnJhcnkoImJpb21hUnQiKQ0KYGBgDQoNCiMjIElJLiBEb3dubG9hZGluZyBUQ0dBIG1pUk5BIGV4cHJlc3Npb24gZGF0YSANCg0KRG93bmxvYWQgbWlSTkEgZXhwcmVzc2lvbiBkYXRhIGZyb20gVGhlIENhbmNlciBHZW5vbWUgQXRsYXMgKFRDR0EpOg0KLSBgVENHQS1DT0FEYCByZWZlcnMgdG8gdGhlIGJpb3NwZWNpbWVuIGRhdGEgZm9yIGNvbG9uIGFkZW5vY2FyY2lub21hLg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCnF1ZXJ5X3R1bW9yIDwtIEdEQ3F1ZXJ5KA0KICBwcm9qZWN0ID0gIlRDR0EtQ09BRCIsDQogIGRhdGEuY2F0ZWdvcnkgPSAiVHJhbnNjcmlwdG9tZSBQcm9maWxpbmciLA0KICBkYXRhLnR5cGUgPSAibWlSTkEgRXhwcmVzc2lvbiBRdWFudGlmaWNhdGlvbiIsDQogIGV4cGVyaW1lbnRhbC5zdHJhdGVneSA9ICJtaVJOQS1TZXEiLA0KICBhY2Nlc3MgPSAib3BlbiIsDQogIHNhbXBsZS50eXBlID0gIlByaW1hcnkgVHVtb3IiDQopDQp0dW1vciA8LSBnZXRSZXN1bHRzKHF1ZXJ5X3R1bW9yKQ0KdHVtb3INCmBgYA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCnF1ZXJ5X25vcm1hbCA8LSBHRENxdWVyeSgNCiAgcHJvamVjdCA9ICJUQ0dBLUNPQUQiLA0KICBkYXRhLmNhdGVnb3J5ID0gIlRyYW5zY3JpcHRvbWUgUHJvZmlsaW5nIiwNCiAgZGF0YS50eXBlID0gIm1pUk5BIEV4cHJlc3Npb24gUXVhbnRpZmljYXRpb24iLA0KICBleHBlcmltZW50YWwuc3RyYXRlZ3kgPSAibWlSTkEtU2VxIiwNCiAgYWNjZXNzID0gIm9wZW4iLA0KICBzYW1wbGUudHlwZSA9ICJTb2xpZCBUaXNzdWUgTm9ybWFsIg0KKQ0Kbm9ybWFsIDwtIGdldFJlc3VsdHMocXVlcnlfbm9ybWFsKQ0Kbm9ybWFsDQpgYGANCkNvbnNpZGVyIG9ubHkgc2FtcGxlcyB3aXRoIGJvdGggbm9ybWFsIGFuZCBtYWxpZ25hbnQgdGlzc3Vlcy4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQpzdWJtaXR0ZXJfaWRzIDwtIGlubmVyX2pvaW4odHVtb3IsIG5vcm1hbCwgYnkgPSAiY2FzZXMuc3VibWl0dGVyX2lkIikgJT4lDQogIGRwbHlyOjpzZWxlY3QoY2FzZXMuc3VibWl0dGVyX2lkKQ0KdHVtb3IgPC0gdHVtb3IgJT4lDQogIGRwbHlyOjpmaWx0ZXIoY2FzZXMuc3VibWl0dGVyX2lkICVpbiUgc3VibWl0dGVyX2lkcyRjYXNlcy5zdWJtaXR0ZXJfaWQpDQpub3JtYWwgPC0gbm9ybWFsICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGNhc2VzLnN1Ym1pdHRlcl9pZCAlaW4lIHN1Ym1pdHRlcl9pZHMkY2FzZXMuc3VibWl0dGVyX2lkKQ0KDQpzYW1wbGVzIDwtIHJiaW5kKHR1bW9yLCBub3JtYWwpDQppbnZpc2libGUodW5pcXVlKHNhbXBsZXMkc2FtcGxlX3R5cGUpKQ0Kc2FtcGxlcw0KYGBgDQoNCkRvd25sb2FkIG9ubHkgc2FtcGxlcyB3aXRoIGJvdGggbm9ybWFsIGFuZCBtYWxpZ25hbnQgdGlzc3Vlcy4NCg0KVG8gaW1wb3NlIHRoaXMgZmlsdGVyaW5nLCB3ZSBzZXQgdGhlIGBiYXJjb2RlYCBhcmd1bWVudCBvZiBgR0RDcXVlcnlgIHRvIGBzYW1wbGVzJHNhbXBsZS5zdWJtaXR0ZXJfaWRgICh3aGljaCB3YXMgZ2VuZXJhdGVkIGluIHRoZSBwcmV2aW91cyBjZWxsKS4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQpxdWVyeV9jb2FkIDwtIEdEQ3F1ZXJ5KA0KICBwcm9qZWN0ID0gIlRDR0EtQ09BRCIsDQogIGRhdGEuY2F0ZWdvcnkgPSAiVHJhbnNjcmlwdG9tZSBQcm9maWxpbmciLA0KICBkYXRhLnR5cGUgPSAibWlSTkEgRXhwcmVzc2lvbiBRdWFudGlmaWNhdGlvbiIsDQogIGV4cGVyaW1lbnRhbC5zdHJhdGVneSA9ICJtaVJOQS1TZXEiLA0KICBhY2Nlc3MgPSAib3BlbiIsDQogIHNhbXBsZS50eXBlID0gYygiU29saWQgVGlzc3VlIE5vcm1hbCIsICJQcmltYXJ5IFR1bW9yIiksDQogIGJhcmNvZGUgPSBhcy5saXN0KHNhbXBsZXMkc2FtcGxlLnN1Ym1pdHRlcl9pZCkNCikNCmBgYA0KSWYgdGhpcyBpcyB5b3VyIGZpcnN0IHRpbWUgcnVubmluZyB0aGlzIG5vdGVib29rIChpLmUuLCB5b3UgaGF2ZSBub3QgeWV0IGRvd25sb2FkZWQgdGhlIHJlc3VsdHMgb2YgdGhlIHF1ZXJ5IGluIHRoZSBwcmV2aW91cyBibG9jayksIHVuY29tbWVudCB0aGUgY29kZSBibG9jayBiZWxvdy4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQpHRENfRElSID0gIi4uL2RhdGEvcHVibGljL0dEQ2RhdGEiDQoNCiMgR0RDZG93bmxvYWQoDQojICAgcXVlcnlfY29hZCwNCiMgICBkaXJlY3RvcnkgPSBHRENfRElSDQojICkNCmBgYA0KDQpSdW5uaW5nIHRoZSBjb2RlIGJsb2NrIGFib3ZlIHNob3VsZCBnZW5lcmF0ZSBhbmQgcG9wdWxhdGUgYSBkaXJlY3RvcnkgbmFtZWQgYEdEQ2RhdGFgLg0KDQojIyBJSUkuIERhdGEgcHJlcHJvY2Vzc2luZw0KDQpDb25zdHJ1Y3QgdGhlIFJOQS1zZXEgY291bnQgbWF0cml4Lg0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHJlc3VsdHM9ImhpZGUifQ0KdGNnYV9jb2FkX2RhdGEgPC0gR0RDcHJlcGFyZSgNCiAgcXVlcnlfY29hZCwgDQogIGRpcmVjdG9yeSA9IEdEQ19ESVIsDQogIHN1bW1hcml6ZWRFeHBlcmltZW50ID0gVFJVRQ0KKQ0KYGBgDQoNCmBgYHtyfQ0Kcm93bmFtZXModGNnYV9jb2FkX2RhdGEpIDwtIHRjZ2FfY29hZF9kYXRhJG1pUk5BX0lEDQpjb3VudF9tYXRyaXggPC0gdGNnYV9jb2FkX2RhdGFbLCBjb2xuYW1lcyh0Y2dhX2NvYWRfZGF0YSlbZ3JlcCgiY291bnQiLCBjb2xuYW1lcyh0Y2dhX2NvYWRfZGF0YSkpXV0NCmNvbG5hbWVzKGNvdW50X21hdHJpeCkgPC0gZ3N1YigicmVhZF9jb3VudF8iLCAiIiwgY29sbmFtZXMoY291bnRfbWF0cml4KSkNCg0KIyBSZW1vdmUgZHVwbGljYXRlIGVudHJpZXMNCmNvdW50X21hdHJpeF9kZiA8LSBkYXRhLmZyYW1lKGNvdW50X21hdHJpeCkNCmNvdW50X21hdHJpeF9kZiA8LSBjb3VudF9tYXRyaXhfZGZbIWR1cGxpY2F0ZWQoY291bnRfbWF0cml4X2RmKSwgXQ0KY291bnRfbWF0cml4IDwtIGRhdGEubWF0cml4KGNvdW50X21hdHJpeF9kZikNCnJvd25hbWVzKGNvdW50X21hdHJpeCkgPC0gY2xlYW5pZChyb3duYW1lcyhjb3VudF9tYXRyaXgpKQ0KY291bnRfbWF0cml4IDwtIGNvdW50X21hdHJpeFshKGR1cGxpY2F0ZWQocm93bmFtZXMoY291bnRfbWF0cml4KSkgfCBkdXBsaWNhdGVkKHJvd25hbWVzKGNvdW50X21hdHJpeCksIGZyb21MYXN0ID0gVFJVRSkpLCBdDQoNCmhlYWQoY291bnRfbWF0cml4WzE6NSwgMTo0XSkNCmBgYA0KRm9ybWF0IHRoZSBgc2FtcGxlc2AgdGFibGUgc28gdGhhdCBpdCBjYW4gYmUgZmVkIGFzIGlucHV0IHRvIERFU2VxMi4NCg0KYGBge3J9DQpyb3duYW1lcyhzYW1wbGVzKSA8LSBzYW1wbGVzJGNhc2VzDQpzYW1wbGVzIDwtIHNhbXBsZXMgJT4lDQogIGRwbHlyOjpzZWxlY3QoY2FzZSA9ICJjYXNlcy5zdWJtaXR0ZXJfaWQiLCB0eXBlID0gInNhbXBsZV90eXBlIikNCnNhbXBsZXMkdHlwZSA8LSBzdHJfcmVwbGFjZShzYW1wbGVzJHR5cGUsICJTb2xpZCBUaXNzdWUgTm9ybWFsIiwgIm5vcm1hbCIpDQpzYW1wbGVzJHR5cGUgPC0gc3RyX3JlcGxhY2Uoc2FtcGxlcyR0eXBlLCAiUHJpbWFyeSBUdW1vciIsICJ0dW1vciIpDQpgYGANCg0KREVTZXEyIHJlcXVpcmVzIHRoZSByb3cgbmFtZXMgb2YgYHNhbXBsZXNgIHNob3VsZCBiZSBpZGVudGljYWwgdG8gdGhlIGNvbHVtbiBuYW1lcyBvZiBgY291bnRfbWF0cml4YC4NCg0KYGBge3IsIGVjaG8gPSBUUlVFLCByZXN1bHRzPSJoaWRlIn0NCmNvbG5hbWVzKGNvdW50X21hdHJpeCkgPC0gZ3N1Yih4ID0gY29sbmFtZXMoY291bnRfbWF0cml4KSwgcGF0dGVybiA9ICJcXC4iLCByZXBsYWNlbWVudCA9ICItIikNCmNvdW50X21hdHJpeCA8LSBjb3VudF9tYXRyaXhbLCByb3duYW1lcyhzYW1wbGVzKV0NCg0KIyBTYW5pdHkgY2hlY2sNCmFsbChjb2xuYW1lcyhjb3VudF9tYXRyaXgpID09IHJvd25hbWVzKHNhbXBsZXMpKQ0KYGBgDQoNCiMjIElWLiBEaWZmZXJlbnRpYWwgbWlSTkEgZXhwcmVzc2lvbiBhbmFseXNpcw0KDQpSZWZlcmVuY2VzOiANCg0KLSBPZmZpY2lhbCBkb2N1bWVudGF0aW9uOiBodHRwczovL3d3dy5iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy92aWduZXR0ZXMvREVTZXEyL2luc3QvZG9jL0RFU2VxMi5odG1sDQotIEdvb2QgYmFsYW5jZSBvZiB0aGVvcnkgYW5kIGhhbmRzLW9uOiBodHRwczovL2hiY3RyYWluaW5nLmdpdGh1Yi5pby9ER0Vfd29ya3Nob3AvbGVzc29ucy8wNF9ER0VfREVTZXEyX2FuYWx5c2lzLmh0bWwNCi0gUXVhbGl0eSBjb250cm9sOiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvUk5Bc2VxUUMvdmlnbmV0dGVzL2ludHJvZHVjdGlvbi5odG1sDQoNCkNvbnN0cnVjdCB0aGUgYERFU2VxRGF0YVNldGAgb2JqZWN0Lg0KDQpgYGB7cn0NCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KA0KICBjb3VudERhdGEgPSBjb3VudF9tYXRyaXgsDQogIGNvbERhdGEgPSBzYW1wbGVzLA0KICBkZXNpZ24gPSB+dHlwZQ0KKQ0KYGBgDQoNCiMjIyBRdWFsaXR5IENvbnRyb2wNCg0KRGlzcGxheSBxdWFsaXR5IGNvbnRyb2wgKFFDKSBwbG90cyAocmVmZXIgdG8gaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1JOQXNlcVFDL3ZpZ25ldHRlcy9pbnRyb2R1Y3Rpb24uaHRtbCkNCg0KLSBUb3RhbCBzYW1wbGUgY291bnRzICANCiAgLSBUb3RhbCBudW1iZXIgb2YgY291bnRzIGZvciBlYWNoIHNhbXBsZQ0KICAtIFdlIHR5cGljYWxseSBleHBlY3QgYWxsIHNhbXBsZXMgdG8gaGF2ZSB0b3RhbCBjb3VudHMgd2l0aGluIHRoZSBzYW1lIG9yZGVyIG9mIG1hZ25pdHVkZQ0KICANCi0gTGlicmFyeSBjb21wbGV4aXR5DQogIC0gV2hhdCBmcmFjdGlvbiBvZiBjb3VudHMgaXMgdGFrZW4gdXAgYnkgd2hhdCBmcmFjdGlvbiBvZiBnZW5lcw0KICAtIFNhbXBsZXMgc2hvd2luZyBhIGRpZmZlcmVudCBsaWJyYXJ5IGNvbXBsZXhpdHkgdGhhbiB0aGUgcmVzdCBtaWdodCBiZSBjb25zaWRlcmVkIGxvdyBxdWFsaXR5DQogIA0KLSBHZW5lIGRldGVjdGlvbg0KICAtIE51bWJlciBvZiBkZXRlY3RlZCBnZW5lcyBmb3IgZWFjaCBzYW1wbGUNCiAgDQoqKkNBVkVBVDoqKiBUaGVyZSBzZWVtIHRvIGJlIHNvbWUgb3V0bGllcnMg4oCUIGJ1dCB3ZSBkZWZlciBoYW5kbGluZyB0aGVtIGZvciBub3chDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KcGxvdF90b3RhbF9jb3VudHMoZGRzKQ0KcGxvdF9saWJyYXJ5X2NvbXBsZXhpdHkoZGRzKQ0KcGxvdF9nZW5lX2RldGVjdGlvbihkZHMpDQpgYGANClBlcmZvcm0gbWlSTkEgZmlsdGVyaW5nLg0KDQpXZSBkZXRlcm1pbmVkIGBtaW5fY291bnRgIGVtcGlyaWNhbGx5IGJ5IGxvb2tpbmcgYXQgdGhlIHJlZCB0cmVuZCBsaW5lIGluIHRoZSB2YXJpYW5jZSBzdGFiaWxpemF0aW9uIHBsb3QuIElkZWFsbHksIHRoaXMgdHJlbmQgbGluZSBzaG91bGQgYmUgZmxhdCAoaS5lLiwgc3RhYmxlKS4NCg0KYGBge3J9DQpkZHMgPC0gZmlsdGVyX2dlbmVzKGRkcywgbWluX2NvdW50ID0gMTApDQpgYGANCg0KVHJhbnNmb3JtIHRoZSByZWFkIGNvdW50cy4NCg0KRnJvbSBodHRwczovL2NoaXBzdGVyLmNzYy5maS9tYW51YWwvZGVzZXEyLXRyYW5zZm9ybS5odG1sOiA8YnI+DQpZb3UgY2FuIHVzZSB0aGUgcmVzdWx0aW5nIHRyYW5zZm9ybWVkIHZhbHVlcyBvbmx5IGZvciB2aXN1YWxpemF0aW9uIGFuZCBjbHVzdGVyaW5nLCBub3QgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIHdoaWNoIG5lZWRzIHJhdyBjb3VudHMuDQoNCmBgYHtyfQ0KZGRzIDwtIGVzdGltYXRlU2l6ZUZhY3RvcnMoZGRzKQ0KbnN1YiA8LSBzdW0ocm93TWVhbnMoY291bnRzKGRkcywgbm9ybWFsaXplZCA9IFRSVUUpKSA+IDEwKQ0KdnNkIDwtIHZzdChkZHMsIG5zdWIgPSBuc3ViKQ0KbWVhbl9zZF9wbG90KHZzZCkNCmBgYA0KDQpDaGVjayB0aGUgY2x1c3RlcmluZyBvZiB0aGUgc2FtcGxlcy4gDQoNCklmIHlvdSBlbmNvdW50ZXIgdGhlIGVycm9yIGBFcnJvciBpbiBsb2FkTmFtZXNwYWNlKHgpIDogdGhlcmUgaXMgbm8gcGFja2FnZSBjYWxsZWQgJ0NvbXBsZXhIZWF0bWFwJ2AsIHVuY29tbWVudCBhbmQgcnVuIHRoZSBmb2xsb3dpbmcgY29kZSBibG9jazoNCg0KYGBge3J9DQojIGluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJqb2tlcmdvby9Db21wbGV4SGVhdG1hcCIpDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTE1fQ0Kc2V0LnNlZWQoNDIpDQpwbG90X3NhbXBsZV9jbHVzdGVyaW5nKHZzZCwgYW5ub192YXJzID0gYygidHlwZSIpLCBkaXN0YW5jZSA9ICJldWNsaWRlYW4iKQ0KYGBgDQoNClBlcmZvcm0gcHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcyAoUENBKS4NCg0KYGBge3J9DQpwbG90X3BjYSh2c2QsIFBDX3ggPSAxLCBQQ195ID0gMiwgc2hhcGVfYnkgPSAidHlwZSIpDQpgYGANCiMjIyBSZWd1bGF0ZWQgQ2VsbCBEZWF0aA0KDQpSZWZlciB0byBgMS4gRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAtIE1TaWdEQiBHZW5lIFNldHMgKyBHVEV4IFRQTS5SbWRgIGZvciBtb3JlIGRldGFpbGVkIGRvY3VtZW50YXRpb24gb24gb2J0YWluaW5nIHRoZSBnZW5lIHNldHMuDQoNCiMjIyMgTWFwcGluZyBtaVJOQXMgdG8gdGFyZ2V0IG1STkFzDQoNCldlIGFyZSBnb2luZyB0byByZWZlciB0byBtaVJEQiB0byBmb3IgdGhlIG1pUk5BLW1STkEgbWFwcGluZzogaHR0cHM6Ly9hY2FkZW1pYy5vdXAuY29tL25hci9hcnRpY2xlLzQ4L0QxL0QxMjcvNTU1NzcyOQ0KDQpUaGUgZmlyc3QgY29sdW1uIG9mIHRoZSBkYXRhc2V0IGxpc3RzIHRoZSBtaVJOQXMsIHdoaWxlIHRoZSBzZWNvbmQgY29sdW1uIGxpc3RzIHRoZSBtUk5BcyAobW9yZSBzcGVjaWZpY2FsbHksIHRoZSBSZWZTZXEgSURzIG9mIHRoZSBtUk5BcykuDQpIb3dldmVyLCBvdXIgZ2VuZSBzZXRzIGxpc3QgdGhlIG1STkFzIG9mIGludGVyZXN0IChpLmUuLCB0aG9zZSBpbnZvbHZlZCBpbiByZWd1bGF0ZWQgY2VsbCBkZWF0aCkgdXNpbmcgdGhlaXIgZ2VuZSBzeW1ib2xzLiA8YnI+DQpIZW5jZSwgd2UgbmVlZCB0byBwZXJmb3JtIHNvbWUgcHJlcHJvY2Vzc2luZyB0byBjb252ZXJ0IHRoZSBnZW5lIHN5bWJvbHMgdG8gUmVmU2VxIElEcy4NCg0KYGBge3J9DQptYXJ0IDwtIHVzZU1hcnQoYmlvbWFydCA9ICJlbnNlbWJsIiwgZGF0YXNldCA9ICJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiKQ0KYGBgDQoNCkFsdGVybmF0aXZlIG1pUk5BLW1STkEgbWFwcGluZyB0b29scy9kYXRhYmFzZXM6DQoNCi0gbWlyVGFyUm5hU2VxOiBodHRwczovL2JtY2dlbm9taWNzLmJpb21lZGNlbnRyYWwuY29tL2FydGljbGVzLzEwLjExODYvczEyODY0LTAyMi0wODU1OC13DQotIG11bHRpTWlSOiBodHRwczovL2FjYWRlbWljLm91cC5jb20vbmFyL2FydGljbGUvNDIvMTcvZTEzMy8yOTAyNTA0DQoNCiMjIyMgTmVjcm9wdG9zaXMNCg0KRmV0Y2ggdGhlIG5lY3JvcHRvc2lzIGdlbmUgc2V0Lg0KDQpgYGB7cn0NCm5lY3JvcHRvc2lzLmdlbmVzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJodW1hbiIsIGNhdGVnb3J5ID0gIkM1Iiwgc3ViY2F0ZWdvcnkgPSAiR086QlAiKSAlPiUNCiAgZHBseXI6OmZpbHRlcihnc19uYW1lID09ICJHT0JQX05FQ1JPUFRPVElDX1NJR05BTElOR19QQVRIV0FZIikNCm5lY3JvcHRvc2lzLmdlbmVzDQpgYGANCg0KR2V0IHRoZSBnZW5lIHN5bWJvbHMgb2YgdGhlIGdlbmVzIGluY2x1ZGVkIGluIHRoZSBuZWNyb3B0b3NpcyBnZW5lIHNldCwgYW5kIGNvbnZlcnQgdGhlbSB0byBSZWZTZXEgSURzLg0KDQpgYGB7cn0NCnJjZF9nZW5lX3N5bWJvbHMgPC0gbmVjcm9wdG9zaXMuZ2VuZXMkZ2VuZV9zeW1ib2wNCnJjZF9yZWZzZXEgPC0gZ2V0Qk0oYXR0cmlidXRlcyA9IGMoInJlZnNlcV9tcm5hIiwgImhnbmNfc3ltYm9sIiksIGZpbHRlcnMgPSAiaGduY19zeW1ib2wiLCB2YWx1ZXMgPSByY2RfZ2VuZV9zeW1ib2xzLCBtYXJ0ID0gbWFydCkNCnJjZF9yZWZzZXENCmBgYA0KDQpXcml0ZSB0aGUgUmVmU2VxIElEcyBvZiB0aGUgbVJOQXMgb2YgaW50ZXJlc3QgdG8gYSBmaWxlLg0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHJlc3VsdHM9ImhpZGUifQ0KcmNkX21ybmFfZmlsZSA8LSAiLi4vZGF0YS9wdWJsaWMvcmNkLWdlbmUtbGlzdC9yZWZzZXEvbmVjcm9wdG9zaXMtZ2VuZXMtcmVmc2VxLnR4dCINCnJjZF9yZWZzZXEudW5pcXVlX2lkcyA8LSB1bmlxdWUodW5saXN0KHJjZF9yZWZzZXEkcmVmc2VxX21ybmEpKQ0KcmNkX3JlZnNlcS51bmlxdWVfaWRzIDwtIHJjZF9yZWZzZXEudW5pcXVlX2lkc1shc2FwcGx5KHJjZF9yZWZzZXEudW5pcXVlX2lkcywgaWRlbnRpY2FsLCAiIildDQoNCiMgUmVnZW5lcmF0ZSB0aGUgZmlsZSBldmVyeSB0aW1lDQppZiAoZmlsZS5leGlzdHMocmNkX21ybmFfZmlsZSkpIHsNCiAgZmlsZS5yZW1vdmUocmNkX21ybmFfZmlsZSkNCn0NCg0KaW52aXNpYmxlKGxhcHBseShyY2RfcmVmc2VxLnVuaXF1ZV9pZHMsIHdyaXRlLCByY2RfbXJuYV9maWxlLCBhcHBlbmQgPSBUUlVFLCBuY29sdW1ucyA9IDEpKQ0KYGBgDQoNCkZldGNoIHRoZSBtaVJOQXMgdGFyZ2V0aW5nIHRoZSBtUk5BcyBvZiBpbnRlcmVzdC4NCg0KYGBge3J9DQpuZWNyb3B0b3Npcy5taXJuYSA8LSByZWFkLnRhYmxlKCIuLi9kYXRhL3B1YmxpYy9taVJOQS9uZWNyb3B0b3Npcy1taXJuYS50eHQiKQ0KbmVjcm9wdG9zaXMubWlybmEgPC0gdW5pcXVlKHVubGlzdChuZWNyb3B0b3Npcy5taXJuYSRWMSkpDQpgYGANCg0KRmlsdGVyIHRoZSBnZW5lcyB0byBpbmNsdWRlIG9ubHkgdGhvc2UgaW4gdGhlIG5lY3JvcHRvc2lzIGdlbmUgc2V0Lg0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHJlc3VsdHM9ImhpZGUifQ0KY29hZF9uZWNyb3B0b3NpcyA8LSBjb3VudF9tYXRyaXhbcm93bmFtZXMoY291bnRfbWF0cml4KSAlaW4lIG5lY3JvcHRvc2lzLm1pcm5hLCBdDQpjb2FkX25lY3JvcHRvc2lzIDwtIGNvYWRfbmVjcm9wdG9zaXNbLCByb3duYW1lcyhzYW1wbGVzKV0NCg0KIyBDaGVjayBpZiBhbGwgc2FtcGxlcyBpbiB0aGUgY291bnRzIGRhdGFmcmFtZSBhcmUgaW4gdGhlIHNhbXBsZXMgZGF0YWZyYW1lDQphbGwoY29sbmFtZXMoY29hZF9uZWNyb3B0b3NpcykgPT0gcm93bmFtZXMoc2FtcGxlcykpDQpgYGANCg0KUGVyZm9ybSBkaWZmZXJlbnRpYWwgbWlSTkEgZXhwcmVzc2lvbiBhbmFseXNpcy4NCg0KYGBge3J9DQpkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeCgNCiAgY291bnREYXRhID0gY29hZF9uZWNyb3B0b3NpcywNCiAgY29sRGF0YSA9IHNhbXBsZXMsDQogIGRlc2lnbiA9IH50eXBlDQopDQpkZHMgPC0gZmlsdGVyX2dlbmVzKGRkcywgbWluX2NvdW50ID0gMTApDQpkZHMkdHlwZSA8LSByZWxldmVsKGRkcyR0eXBlLCByZWYgPSAibm9ybWFsIikNCmRkcyA8LSBERVNlcShkZHMpDQpyZXMgPC0gcmVzdWx0cyhkZHMpDQpzdW1tYXJ5KHJlcykNCmBgYA0KDQpQcmV0dGlmeSB0aGUgZGlzcGxheSBvZiByZXN1bHRzLg0KDQpgYGB7cn0NCmRlc2VxLnJlc3VsdHMgPC0gcmVzDQpkZXNlcS5iYmwuZGF0YSA8LSBkYXRhLmZyYW1lKA0KICByb3cubmFtZXMgPSByb3duYW1lcyhkZXNlcS5yZXN1bHRzKSwNCiAgYmFzZU1lYW4gPSBkZXNlcS5yZXN1bHRzJGJhc2VNZWFuLA0KICBsb2cyRm9sZENoYW5nZSA9IGRlc2VxLnJlc3VsdHMkbG9nMkZvbGRDaGFuZ2UsDQogIGxmY1NFID0gZGVzZXEucmVzdWx0cyRsZmNTRSwNCiAgc3RhdCA9IGRlc2VxLnJlc3VsdHMkc3RhdCwNCiAgcHZhbHVlID0gZGVzZXEucmVzdWx0cyRwdmFsdWUsDQogIHBhZGogPSBkZXNlcS5yZXN1bHRzJHBhZGosDQogIGNhbmNlcl90eXBlID0gIkNvbG9uIg0KKQ0KZGVzZXEuYmJsLmRhdGENCmBgYA0KDQpGaWx0ZXIgYmFzZWQgb24gcC12YWx1ZSBhbmQgbG9nIGZvbGQgY2hhbmdlIGN1dG9mZnMuDQoNCmBgYHtyfQ0KZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQgPC0gZHBseXI6OmZpbHRlcihkZXNlcS5iYmwuZGF0YSwgYWJzKGxvZzJGb2xkQ2hhbmdlKSA+PSAxLjUgJiBwYWRqIDwgMC4wNSkNCmRlc2VxLmJibC5kYXRhLmZpbHRlcmVkDQpgYGANCg0KUGxvdCB0aGUgcmVzdWx0cy4NCg0KYGBge3IsIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTE1fQ0KZ2dwbG90KGRlc2VxLmJibC5kYXRhLmZpbHRlcmVkLCBhZXMoeCA9IGNhbmNlcl90eXBlLCB5ID0gcm93bmFtZXMoZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQpLCBzaXplID0gcGFkaiwgZmlsbCA9IGxvZzJGb2xkQ2hhbmdlKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41LCBzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIpICsNCiAgc2NhbGVfc2l6ZSh0cmFucyA9ICJyZXZlcnNlIikgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIiwgbGltaXRzID0gYyhtaW4oZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQkbG9nMkZvbGRDaGFuZ2UpLCBtYXgoZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQkbG9nMkZvbGRDaGFuZ2UpKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICBsYWJzKHNpemUgPSAiQWRqdXN0ZWQgcC12YWx1ZSIsIGZpbGwgPSAibG9nMiBGQyIsIHggPSAiQ2FuY2VyIHR5cGUiLCB5ID0gIm1pUk5BIikNCmBgYA0KIyMjIyBGZXJyb3B0b3Npcw0KDQpGZXRjaCB0aGUgZmVycm9wdG9zaXMgZ2VuZSBzZXQuDQoNCmBgYHtyfQ0KZmVycm9wdG9zaXMuZ2VuZXMgPC0gbXNpZ2RicihzcGVjaWVzID0gImh1bWFuIiwgY2F0ZWdvcnkgPSAiQzIiLCBzdWJjYXRlZ29yeSA9ICJDUDpXSUtJUEFUSFdBWVMiKSAlPiUNCiAgZHBseXI6OmZpbHRlcihnc19uYW1lID09ICJXUF9GRVJST1BUT1NJUyIpDQpmZXJyb3B0b3Npcy5nZW5lcw0KYGBgDQoNCkdldCB0aGUgZ2VuZSBzeW1ib2xzIG9mIHRoZSBnZW5lcyBpbmNsdWRlZCBpbiB0aGUgZmVycm9wdG9zaXMgZ2VuZSBzZXQsIGFuZCBjb252ZXJ0IHRoZW0gdG8gUmVmU2VxIElEcy4NCg0KYGBge3J9DQpyY2RfZ2VuZV9zeW1ib2xzIDwtIGZlcnJvcHRvc2lzLmdlbmVzJGdlbmVfc3ltYm9sDQpyY2RfcmVmc2VxIDwtIGdldEJNKGF0dHJpYnV0ZXMgPSBjKCJyZWZzZXFfbXJuYSIsICJoZ25jX3N5bWJvbCIpLCBmaWx0ZXJzID0gImhnbmNfc3ltYm9sIiwgdmFsdWVzID0gcmNkX2dlbmVfc3ltYm9scywgbWFydCA9IG1hcnQpDQpyY2RfcmVmc2VxDQpgYGANCg0KV3JpdGUgdGhlIFJlZlNlcSBJRHMgb2YgdGhlIG1STkFzIG9mIGludGVyZXN0IHRvIGEgZmlsZS4NCg0KYGBge3IsIGVjaG8gPSBUUlVFLCByZXN1bHRzPSJoaWRlIn0NCnJjZF9tcm5hX2ZpbGUgPC0gIi4uL2RhdGEvcHVibGljL3JjZC1nZW5lLWxpc3QvcmVmc2VxL2ZlcnJvcHRvc2lzLWdlbmVzLXJlZnNlcS50eHQiDQpyY2RfcmVmc2VxLnVuaXF1ZV9pZHMgPC0gdW5pcXVlKHVubGlzdChyY2RfcmVmc2VxJHJlZnNlcV9tcm5hKSkNCnJjZF9yZWZzZXEudW5pcXVlX2lkcyA8LSByY2RfcmVmc2VxLnVuaXF1ZV9pZHNbIXNhcHBseShyY2RfcmVmc2VxLnVuaXF1ZV9pZHMsIGlkZW50aWNhbCwgIiIpXQ0KDQojIFJlZ2VuZXJhdGUgdGhlIGZpbGUgZXZlcnkgdGltZQ0KaWYgKGZpbGUuZXhpc3RzKHJjZF9tcm5hX2ZpbGUpKSB7DQogIGZpbGUucmVtb3ZlKHJjZF9tcm5hX2ZpbGUpDQp9DQoNCmludmlzaWJsZShsYXBwbHkocmNkX3JlZnNlcS51bmlxdWVfaWRzLCB3cml0ZSwgcmNkX21ybmFfZmlsZSwgYXBwZW5kID0gVFJVRSwgbmNvbHVtbnMgPSAxKSkNCmBgYA0KDQpGZXRjaCB0aGUgbWlSTkFzIHRhcmdldGluZyB0aGUgbVJOQXMgb2YgaW50ZXJlc3QuDQoNCmBgYHtyfQ0KZmVycm9wdG9zaXMubWlybmEgPC0gcmVhZC50YWJsZSgiLi4vZGF0YS9wdWJsaWMvbWlSTkEvZmVycm9wdG9zaXMtbWlybmEudHh0IikNCmZlcnJvcHRvc2lzLm1pcm5hIDwtIHVuaXF1ZSh1bmxpc3QoZmVycm9wdG9zaXMubWlybmEkVjEpKQ0KYGBgDQoNCkZpbHRlciB0aGUgZ2VuZXMgdG8gaW5jbHVkZSBvbmx5IHRob3NlIGluIHRoZSBmZXJyb3B0b3NpcyBnZW5lIHNldC4NCg0KYGBge3IsIGVjaG8gPSBUUlVFLCByZXN1bHRzPSJoaWRlIn0NCmNvYWRfZmVycm9wdG9zaXMgPC0gY291bnRfbWF0cml4W3Jvd25hbWVzKGNvdW50X21hdHJpeCkgJWluJSBmZXJyb3B0b3Npcy5taXJuYSwgXQ0KY29hZF9mZXJyb3B0b3NpcyA8LSBjb2FkX2ZlcnJvcHRvc2lzWywgcm93bmFtZXMoc2FtcGxlcyldDQoNCiMgQ2hlY2sgaWYgYWxsIHNhbXBsZXMgaW4gdGhlIGNvdW50cyBkYXRhZnJhbWUgYXJlIGluIHRoZSBzYW1wbGVzIGRhdGFmcmFtZQ0KYWxsKGNvbG5hbWVzKGNvYWRfZmVycm9wdG9zaXMpID09IHJvd25hbWVzKHNhbXBsZXMpKQ0KYGBgDQpQZXJmb3JtIGRpZmZlcmVudGlhbCBtaVJOQSBleHByZXNzaW9uIGFuYWx5c2lzLg0KDQpgYGB7cn0NCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KA0KICBjb3VudERhdGEgPSBjb2FkX2ZlcnJvcHRvc2lzLA0KICBjb2xEYXRhID0gc2FtcGxlcywNCiAgZGVzaWduID0gfnR5cGUNCikNCmRkcyA8LSBmaWx0ZXJfZ2VuZXMoZGRzLCBtaW5fY291bnQgPSAxMCkNCmRkcyR0eXBlIDwtIHJlbGV2ZWwoZGRzJHR5cGUsIHJlZiA9ICJub3JtYWwiKQ0KZGRzIDwtIERFU2VxKGRkcykNCnJlcyA8LSByZXN1bHRzKGRkcykNCnN1bW1hcnkocmVzKQ0KYGBgDQpQcmV0dGlmeSB0aGUgZGlzcGxheSBvZiByZXN1bHRzLg0KDQpgYGB7cn0NCmRlc2VxLnJlc3VsdHMgPC0gcmVzDQpkZXNlcS5iYmwuZGF0YSA8LSBkYXRhLmZyYW1lKA0KICByb3cubmFtZXMgPSByb3duYW1lcyhkZXNlcS5yZXN1bHRzKSwNCiAgYmFzZU1lYW4gPSBkZXNlcS5yZXN1bHRzJGJhc2VNZWFuLA0KICBsb2cyRm9sZENoYW5nZSA9IGRlc2VxLnJlc3VsdHMkbG9nMkZvbGRDaGFuZ2UsDQogIGxmY1NFID0gZGVzZXEucmVzdWx0cyRsZmNTRSwNCiAgc3RhdCA9IGRlc2VxLnJlc3VsdHMkc3RhdCwNCiAgcHZhbHVlID0gZGVzZXEucmVzdWx0cyRwdmFsdWUsDQogIHBhZGogPSBkZXNlcS5yZXN1bHRzJHBhZGosDQogIGNhbmNlcl90eXBlID0gIkNvbG9uIg0KKQ0KZGVzZXEuYmJsLmRhdGENCmBgYA0KDQpGaWx0ZXIgYmFzZWQgb24gcC12YWx1ZSBhbmQgbG9nIGZvbGQgY2hhbmdlIGN1dG9mZnMuDQoNCmBgYHtyfQ0KZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQgPC0gZHBseXI6OmZpbHRlcihkZXNlcS5iYmwuZGF0YSwgYWJzKGxvZzJGb2xkQ2hhbmdlKSA+PSAxLjUgJiBwYWRqIDwgMC4wNSkNCmRlc2VxLmJibC5kYXRhLmZpbHRlcmVkDQpgYGANCg0KUGxvdCB0aGUgcmVzdWx0cy4NCg0KYGBge3IsIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTQ1fQ0KZ2dwbG90KGRlc2VxLmJibC5kYXRhLmZpbHRlcmVkLCBhZXMoeCA9IGNhbmNlcl90eXBlLCB5ID0gcm93bmFtZXMoZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQpLCBzaXplID0gcGFkaiwgZmlsbCA9IGxvZzJGb2xkQ2hhbmdlKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41LCBzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIpICsNCiAgc2NhbGVfc2l6ZSh0cmFucyA9ICJyZXZlcnNlIikgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIiwgbGltaXRzID0gYyhtaW4oZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQkbG9nMkZvbGRDaGFuZ2UpLCBtYXgoZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQkbG9nMkZvbGRDaGFuZ2UpKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICBsYWJzKHNpemUgPSAiQWRqdXN0ZWQgcC12YWx1ZSIsIGZpbGwgPSAibG9nMiBGQyIsIHggPSAiQ2FuY2VyIHR5cGUiLCB5ID0gIm1pUk5BIikNCmBgYA0KDQojIyMjIFB5cm9wdG9zaXMNCg0KRmV0Y2ggdGhlIHB5cm9wdG9zaXMgZ2VuZSBzZXQuDQoNCmBgYHtyfQ0KcHlyb3B0b3Npcy5nZW5lcyA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiaHVtYW4iLCBjYXRlZ29yeSA9ICJDMiIsIHN1YmNhdGVnb3J5ID0gIkNQOlJFQUNUT01FIikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoZ3NfbmFtZSA9PSAiUkVBQ1RPTUVfUFlST1BUT1NJUyIpDQpweXJvcHRvc2lzLmdlbmVzDQpgYGANCg0KR2V0IHRoZSBnZW5lIHN5bWJvbHMgb2YgdGhlIGdlbmVzIGluY2x1ZGVkIGluIHRoZSBweXJvcHRvc2lzIGdlbmUgc2V0LCBhbmQgY29udmVydCB0aGVtIHRvIFJlZlNlcSBJRHMuDQoNCmBgYHtyfQ0KcmNkX2dlbmVfc3ltYm9scyA8LSBweXJvcHRvc2lzLmdlbmVzJGdlbmVfc3ltYm9sDQpyY2RfcmVmc2VxIDwtIGdldEJNKGF0dHJpYnV0ZXMgPSBjKCJyZWZzZXFfbXJuYSIsICJoZ25jX3N5bWJvbCIpLCBmaWx0ZXJzID0gImhnbmNfc3ltYm9sIiwgdmFsdWVzID0gcmNkX2dlbmVfc3ltYm9scywgbWFydCA9IG1hcnQpDQpyY2RfcmVmc2VxDQpgYGANCldyaXRlIHRoZSBSZWZTZXEgSURzIG9mIHRoZSBtUk5BcyBvZiBpbnRlcmVzdCB0byBhIGZpbGUuDQoNCmBgYHtyLCBlY2hvID0gVFJVRSwgcmVzdWx0cz0iaGlkZSJ9DQpyY2RfbXJuYV9maWxlIDwtICIuLi9kYXRhL3B1YmxpYy9yY2QtZ2VuZS1saXN0L3JlZnNlcS9weXJvcHRvc2lzLWdlbmVzLXJlZnNlcS50eHQiDQpyY2RfcmVmc2VxLnVuaXF1ZV9pZHMgPC0gdW5pcXVlKHVubGlzdChyY2RfcmVmc2VxJHJlZnNlcV9tcm5hKSkNCnJjZF9yZWZzZXEudW5pcXVlX2lkcyA8LSByY2RfcmVmc2VxLnVuaXF1ZV9pZHNbIXNhcHBseShyY2RfcmVmc2VxLnVuaXF1ZV9pZHMsIGlkZW50aWNhbCwgIiIpXQ0KDQojIFJlZ2VuZXJhdGUgdGhlIGZpbGUgZXZlcnkgdGltZQ0KaWYgKGZpbGUuZXhpc3RzKHJjZF9tcm5hX2ZpbGUpKSB7DQogIGZpbGUucmVtb3ZlKHJjZF9tcm5hX2ZpbGUpDQp9DQoNCmludmlzaWJsZShsYXBwbHkocmNkX3JlZnNlcS51bmlxdWVfaWRzLCB3cml0ZSwgcmNkX21ybmFfZmlsZSwgYXBwZW5kID0gVFJVRSwgbmNvbHVtbnMgPSAxKSkNCmBgYA0KDQpGZXRjaCB0aGUgbWlSTkFzIHRhcmdldGluZyB0aGUgbVJOQXMgb2YgaW50ZXJlc3QuDQoNCmBgYHtyfQ0KcHlyb3B0b3Npcy5taXJuYSA8LSByZWFkLnRhYmxlKCIuLi9kYXRhL3B1YmxpYy9taVJOQS9weXJvcHRvc2lzLW1pcm5hLnR4dCIpDQpweXJvcHRvc2lzLm1pcm5hIDwtIHVuaXF1ZSh1bmxpc3QocHlyb3B0b3Npcy5taXJuYSRWMSkpDQpgYGANCg0KRmlsdGVyIHRoZSBnZW5lcyB0byBpbmNsdWRlIG9ubHkgdGhvc2UgaW4gdGhlIHB5cm9wdG9zaXMgZ2VuZSBzZXQuDQoNCmBgYHtyLCBlY2hvID0gVFJVRSwgcmVzdWx0cz0iaGlkZSJ9DQpjb2FkX3B5cm9wdG9zaXMgPC0gY291bnRfbWF0cml4W3Jvd25hbWVzKGNvdW50X21hdHJpeCkgJWluJSBweXJvcHRvc2lzLm1pcm5hLCBdDQpjb2FkX3B5cm9wdG9zaXMgPC0gY29hZF9weXJvcHRvc2lzWywgcm93bmFtZXMoc2FtcGxlcyldDQoNCiMgQ2hlY2sgaWYgYWxsIHNhbXBsZXMgaW4gdGhlIGNvdW50cyBkYXRhZnJhbWUgYXJlIGluIHRoZSBzYW1wbGVzIGRhdGFmcmFtZQ0KYWxsKGNvbG5hbWVzKGNvYWRfcHlyb3B0b3NpcykgPT0gcm93bmFtZXMoc2FtcGxlcykpDQpgYGANCg0KUGVyZm9ybSBkaWZmZXJlbnRpYWwgbWlSTkEgZXhwcmVzc2lvbiBhbmFseXNpcy4NCg0KYGBge3J9DQpkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeCgNCiAgY291bnREYXRhID0gY29hZF9weXJvcHRvc2lzLA0KICBjb2xEYXRhID0gc2FtcGxlcywNCiAgZGVzaWduID0gfnR5cGUNCikNCmRkcyA8LSBmaWx0ZXJfZ2VuZXMoZGRzLCBtaW5fY291bnQgPSAxMCkNCmRkcyR0eXBlIDwtIHJlbGV2ZWwoZGRzJHR5cGUsIHJlZiA9ICJub3JtYWwiKQ0KZGRzIDwtIERFU2VxKGRkcykNCnJlcyA8LSByZXN1bHRzKGRkcykNCnN1bW1hcnkocmVzKQ0KYGBgDQpQcmV0dGlmeSB0aGUgZGlzcGxheSBvZiByZXN1bHRzLg0KDQpgYGB7cn0NCmRlc2VxLnJlc3VsdHMgPC0gcmVzDQpkZXNlcS5iYmwuZGF0YSA8LSBkYXRhLmZyYW1lKA0KICByb3cubmFtZXMgPSByb3duYW1lcyhkZXNlcS5yZXN1bHRzKSwNCiAgYmFzZU1lYW4gPSBkZXNlcS5yZXN1bHRzJGJhc2VNZWFuLA0KICBsb2cyRm9sZENoYW5nZSA9IGRlc2VxLnJlc3VsdHMkbG9nMkZvbGRDaGFuZ2UsDQogIGxmY1NFID0gZGVzZXEucmVzdWx0cyRsZmNTRSwNCiAgc3RhdCA9IGRlc2VxLnJlc3VsdHMkc3RhdCwNCiAgcHZhbHVlID0gZGVzZXEucmVzdWx0cyRwdmFsdWUsDQogIHBhZGogPSBkZXNlcS5yZXN1bHRzJHBhZGosDQogIGNhbmNlcl90eXBlID0gIkNvbG9uIg0KKQ0KZGVzZXEuYmJsLmRhdGENCmBgYA0KDQpGaWx0ZXIgYmFzZWQgb24gcC12YWx1ZSBhbmQgbG9nIGZvbGQgY2hhbmdlIGN1dG9mZnMuDQoNCmBgYHtyfQ0KZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQgPC0gZHBseXI6OmZpbHRlcihkZXNlcS5iYmwuZGF0YSwgYWJzKGxvZzJGb2xkQ2hhbmdlKSA+PSAxLjUgJiBwYWRqIDwgMC4wNSkNCmRlc2VxLmJibC5kYXRhLmZpbHRlcmVkDQpgYGANCg0KDQpQbG90IHRoZSByZXN1bHRzLg0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9MzB9DQpnZ3Bsb3QoZGVzZXEuYmJsLmRhdGEuZmlsdGVyZWQsIGFlcyh4ID0gY2FuY2VyX3R5cGUsIHkgPSByb3duYW1lcyhkZXNlcS5iYmwuZGF0YS5maWx0ZXJlZCksIHNpemUgPSBwYWRqLCBmaWxsID0gbG9nMkZvbGRDaGFuZ2UpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIHNoYXBlID0gMjEsIGNvbG9yID0gImJsYWNrIikgKw0KICBzY2FsZV9zaXplKHRyYW5zID0gInJldmVyc2UiKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiLCBsaW1pdHMgPSBjKG1pbihkZXNlcS5iYmwuZGF0YS5maWx0ZXJlZCRsb2cyRm9sZENoYW5nZSksIG1heChkZXNlcS5iYmwuZGF0YS5maWx0ZXJlZCRsb2cyRm9sZENoYW5nZSkpKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogIGxhYnMoc2l6ZSA9ICJBZGp1c3RlZCBwLXZhbHVlIiwgZmlsbCA9ICJsb2cyIEZDIiwgeCA9ICJDYW5jZXIgdHlwZSIsIHkgPSAibWlSTkEiKQ0KYGBg